--[[
The purpose of this module is to capture information by player
so that things like DKP calculations and lists of loot gained
by player can be done quickly and without much work on the part
of the host.
Technically the data in here is a duplicate of the data within
the auction data list.  I may add an option to not store this
data within SavedVariables to reduce overhead - or perhaps store
only a limited number of players' data.
]]--

SNFDKPItems = { }

SNFLoot = { }  -- public interface

local UlduarItemMatchStrings = {
		".*Wayward Conqueror.*",
		".*Wayward Vanquisher.*",
		".*Wayward Protector.*",
	}
local TOCItemMatchStrings = {
		".*Trophy of the Crusade.*",
	}
local ICCItemMatchStrings = {
		".*Mark of Sanctification.*",
	}
local NaxxItemMatchStrings = {
		".*Lost Conqueror.*",
		".*Lost Vanquisher.*",
		".*Lost Protector.*",
	}
local ProfessionItemMatchStrings = {
		".*Pattern:.*",
		".*Formula.*",
		".*Plans:.*",
	}

local T11ItemMatchStrings = {
		".*of the Forlorn*",
	}

local SpecialReportMatchStrings = {
		{ match = ".*of the Forlorn*", group = "T11N" },
		{ match = ".*5202[567].*", group = "ICCN" },
		{ match = ".*5202[89].*", group = "ICCH" },
		{ match = ".*52030.*", group = "ICCH" },
		{ match = ".*Trophy of the Crusade.*", group = "TOC" },
	}

function SNFLoot:HasLoot(name)

	local rname = SNFPlayer:GetPlayerMain(name)

	return (SNFDKPItems and SNFDKPItems[rname] ~= nil)
end

function SNFLoot:GetInstanceForItem(item)

	local instance, raidsize, difficulty, istracked = "<unknown>", 0, "N", true

	if not item then return instance, raidsize, difficulty, istracked end

	local ilvl = SNFGetItemLevel(item)

--	if not ilvl then
--		SNFDEBUG(2, "ilvl is nil - Unable to determine instance for item "..(item or "nil"))
--		local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType,
--			itemSubType, itemStackCount, itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(item)
--		SNFDEBUG(2, "Item has a type of "..(itemType or "nil"))
--	end

	if ilvl == 372 then
		instance = "T11"
		raidsize = 25
		difficulty = "H"
	elseif ilvl == 359 then
		instance = "T11"
		raidsize = 25
		difficulty = "N"
	elseif ilvl == 277 then
		instance = "ICC"
		raidsize = 25
		difficulty = "H"
	elseif ilvl == 264 or ilvl == 271 then  -- 264 are all bosses except LK, which drops 271
		instance = "ICC"
		raidsize = 25
		difficulty = "N"
	elseif ilvl == 258 then
		instance = "TOC"
		raidsize = 25
		difficulty = "H"
	elseif ilvl == 245 then
		instance = "TOC"
		raidsize = 25
		difficulty = "N"
	elseif ilvl == 239 then
		instance = "ULDUAR"
		raidsize = 25
		difficulty = "H"
--		SNFDEBUG(2, "Instance determination: ULDUAR/25/H/"..ilvl)
	elseif ilvl == 226 or ilvl == 232 then
		instance = "ULDUAR"
		raidsize = 25
		difficulty = "H"
--		SNFDEBUG(2, "Instance determination: ULDUAR/25/H/"..ilvl)
	elseif ilvl == 219 then
		instance = "Ulduar"
		raidsize = 10
		difficulty = "N"
--		SNFDEBUG(2, "Instance determination: ULDUAR/10/N/"..ilvl)
	elseif ilvl == 213 then
		instance = "NAXX"
		raidsize = 25
		difficulty = "N"
	else
		for _, str in ipairs(ProfessionItemMatchStrings) do
			--SNFDEBUG(2, "Checking match string "..(str or "nil"))
			if strmatch(item, str) then
				--SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "PROFESSION"
				raidsize = 25
				difficulty = "N"
				istracked = false
			end
		end
		for _, str in ipairs(NaxxItemMatchStrings) do
			--SNFDEBUG(2, "Checking match string "..(str or "nil"))
			if strmatch(item, str) then
				--SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "NAXX"
				raidsize = 25
				difficulty = "N"
			end
		end
		for _, str in ipairs(UlduarItemMatchStrings) do
			--SNFDEBUG(2, "Checking match string "..(str or "nil"))
			if strmatch(item, str) then
				--SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "ULDUAR"
				raidsize = 25
				difficulty = "N"
			end
		end
		for _, str in ipairs(TOCItemMatchStrings) do
			if strmatch(item, str) then
				--SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "TOC"
				raidsize = 25
				difficulty = "N"
			end
		end
		for _, str in ipairs(ICCItemMatchStrings) do
			if strmatch(item, str) then
--				SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "ICC"
				raidsize = 25
				difficulty = "N"
			end
		end
		for _, str in ipairs(T11ItemMatchStrings) do
			if strmatch(item, str) then
--				SNFDEBUG(2, "Matched "..(str or "nil").." from "..(item or "nil"))
				instance = "T11"
				raidsize = 25
				difficulty = "N"
			end
		end
		if raidsize == 0 then
			SNFDEBUG(2, "Unable to determine instance for item "..(item or "nil"))
			local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType,
				itemSubType, itemStackCount, itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(item)
			SNFDEBUG(2, "Item has a type of "..(itemType or "nil"))
		end
	end
	return instance, raidsize, difficulty, istracked
end



function SNFLoot:AddPlayerLoot(n, bidlevel, raid, loot)

	local lvl = SNFGetItemLevel(loot)

	local instance, raidsize, difficulty, istracked = SNFLoot:GetInstanceForItem(loot)

	if (instance == "<unknown>") then
		SNFDEBUG(2, "Raid "..(raid or "nil").." has unassociated item "..(loot or "nil"))
		return
	end

	SNFAttend:RaidSplitRaidID(raid,instance)

--	if ((instance ~= "TOC" and instance ~= "ICC") and bidlevel ~= "DKP") or raidsize ~= 25 then
--		SNFDEBUG(3, "Skipping loot because it's not TOC and not a DKP item: "..(loot or "nil").." from "..(instance or "nil"))
--		return
--	end

	local name = SNFPlayer:GetPlayerMain(n)
	if not (name and loot and bidlevel) then
		SNFDEBUG(1, "Bad parameter to SNFLoot:AddPlayerLoot("..(name or "nil")..","..(loot or "nil")..","..(bidlevel or "nil")..")")
		return
	end

	if not SNFDKPItems[name] then
		SNFDKPItems[name] = { }
	end
	if not SNFDKPItems[name][bidlevel] then
		SNFDKPItems[name][bidlevel] = { }
	end
	if not SNFDKPItems[name][bidlevel]["Count"] then
		SNFDKPItems[name][bidlevel]["Count"] = 0
	end
	if not SNFDKPItems[name][bidlevel]["Raids"] then
		SNFDKPItems[name][bidlevel]["Raids"] = { }
	end
	if not SNFDKPItems[name][bidlevel]["Raids"][raid] then
		SNFDKPItems[name][bidlevel]["Raids"][raid] = { }
	end

	thisraid = SNFDKPItems[name][bidlevel]["Raids"][raid]

	if not thisraid["Count"] then
		thisraid["Count"] = 0
	end
	SNFDEBUG(3, "Player "..name.." has won "..SNFDKPItems[name][bidlevel]["Count"].." bids of "..bidlevel..
		"("..thisraid["Count"].." this raid)")

	if not thisraid["Loots"] then
		thisraid["Loots"] = { }
	end

	local lootstruct = { item = loot }
	tinsert(thisraid["Loots"], lootstruct)

	if istracked then
		SNFDKPItems[name][bidlevel]["Count"] = SNFDKPItems[name][bidlevel]["Count"] + 1
		thisraid["Count"] = thisraid["Count"] + 1
	end

	if bidlevel == "DKP" then SNFPlayer:ClearPlayerCounts(SNFPlayer:GetPlayerMain(name)) end -- they got a DKP item, so make sure counts are recalculated next time


end

function SNFLoot:GetLootCount(n, bidlevel, raid)


	if not (n and bidlevel) then
		SNFDEBUG(1, "Bad parameter to SNFLoot:GetLootCount("..(n or "nil")..","..(bidlevel or "nil")..","..(raid or "nil")..")")
	end

	local name = SNFPlayer:GetPlayerMain(n)

	if not SNFDKPItems[name] then
		SNFDEBUG(2, "Player "..name.." does not have any calculated loot counts")
		return
	end
	if SNFDKPItems[name][bidlevel] then
		local list = SNFDKPItems[name][bidlevel]
		if not raid then
			if not list["Count"] then
				SNFDEBUG(1, "Count bugged in SNFLoot:GetLootCount()")
				return
			end
			SNFDEBUG(3, "SNFLoot:GetLootCount found global count for "..bidlevel.." of "..list["Count"])
			return list["Count"]
		end
	end
end

function SNFLoot:GetLootCount2(n, bidlevel, raid)


	if not (n and bidlevel) then
		SNFDEBUG(1, "Bad parameter to SNFLoot:GetLootCount("..(n or "nil")..","..(bidlevel or "nil")..","..(raid or "nil")..")")
	end

	local name = SNFPlayer:GetPlayerMain(n)

	if not SNFDKPItems[name] then
		SNFDEBUG(2, "Player "..name.." does not have any calculated loot counts")
		return
	end
	local criteria, compareval = SNFFilter:GetFilterSettings("attend")
	local count

--[[		if (criteria == ">" and key > compareval) or
		   (criteria == "<" and key < compareval) or
		   (criteria == "=" and key == compareval) or
		   (criteria == "==" and key == compareval) then
		   	table.insert(SNFFiltercache[filter], key)
		end
]]--
	if SNFDKPItems[name][bidlevel] then
		local list = SNFDKPItems[name][bidlevel]

		if criteria and compareval then
			if list and list["Raids"] then
				for r, data in pairs(list["Raids"]) do
					if r and type(data) == "table" and data["Count"] and
					((criteria == ">" and r > compareval) or
					(criteria == "<" and r < compareval) or
					(criteria == "=" and r == compareval) or
					(criteria == "==" and r == compareval) or
					(bidlevel == "DKP")) then  -- DKP bypasses all filters and is always counted
						if not raid or (raid and r == raid) then
							count = (count or 0) + data["Count"] -- count stays nil until this statement, useful return information.
						end
					end
				end
			end
		else
			count = list["Count"]
		end
	end
--	if bidlevel and bilevel == "DKP" then
--		count = count -
--	end
	return count
end

function SNFLoot:ScanPastRaid(raid)

	SNFDEBUG(4, "SNFLoot:ScanPastRaid("..(raid or "nil")..")")

--	SNFPRINT(2, "SNFAuctions["..raid.."]", SNFAuctions[raid])

	if not SNFAuctions[raid] then
		SNFDEBUG(0, "No raid, '"..(raid or "nil").."'")
		return
	end
	for i, auction in ipairs(SNFAuctions[raid]) do
		if not auction then
			SNFDEBUG(2, "Bad auction")
		else
			if not auction["winner"] then
				SNFDEBUG(3, "No winner (might have been DE'ed)")
			else
				local name = auction["winner"]
				local rname = SNFPlayer:GetPlayerMain(auction["winner"])
				if not auction["AuctionItem"] then
					SNFDEBUG(2, "Bad AuctionItem")
				else
					local item = auction["AuctionItem"]
					local itemid = SNFGetItemID(item)

					if auction["BidList"] and
					   auction["BidList"][name] and
					   auction["BidList"][name]["level"] then
						local bidlevel = auction["BidList"][name]["level"]
						SNFLoot:AddPlayerLoot(rname, bidlevel, raid, item)
					else
						SNFDEBUG(2, "Cannot find bidlevel for player "..(name or "nil").." in raid "..(raid or "nil").." - skipping item")
					end

				end

			end

		end

	end
end

function SNFLoot:ScanAllRaids()

	SNFDEBUG(0, "Clearing all item data")
	SNFDKPItems = { }

	SNFAttend:ClearRaidSplitCounts()
	for raid, _ in pairs(SNFAuctions) do
		SNFLoot:ScanPastRaid(raid)
	end
	SNFAttend:RaidSplitCountsPrintQuestionable()
end

function SNFLoot:ListPastLoot(name)

	local rname = SNFPlayer:GetPlayerMain(name)
	if not SNFDKPItems or not SNFDKPItems[rname] then
		SNFDEBUG(0, "No loot listed for "..(name or "nil"))
		return
	end

	local init = false
	for bidlevel, biddata in pairs(SNFDKPItems[rname]) do
		if biddata and biddata["Raids"] then
			for raidid, raiddata in pairs(biddata["Raids"]) do
				if raiddata and type(raiddata) == "table" and raiddata["Loots"] then
					for _, loot in pairs(raiddata["Loots"]) do
						if not init then
							SNFDEBUG(0, "Loot for "..(name or "nil"))
							init = true
						end
						SNFDEBUG(0, "    "..bidlevel..", "..raidid..": "..(loot["item"] or "nil"))
					end
				end
			end
		end
	end
	if not init then
		SNFDEBUG(0, "No loot listed for "..(name or "nil"))
	end
end

--SNFMessage:QueueTell("DKP Total (ever earned) = "..(nDKP).." current: "..(nDKP - spent), name)
function SNFLoot:ReplyPastLoot(name)

	local rname = SNFPlayer:GetPlayerMain(name)
	if not SNFDKPItems or not SNFDKPItems[rname] then
		SNFMessage:QueueTell("No loot listed for "..(rname or "nil"), name)
		return
	end

	local init = false
	for bidlevel, biddata in pairs(SNFDKPItems[rname]) do
		if bidlevel ~= "OFF" then
			if biddata and biddata["Raids"] then
				for raidid, raiddata in pairs(biddata["Raids"]) do
					if raiddata and type(raiddata) == "table" and raiddata["Loots"] then
						for _, loot in pairs(raiddata["Loots"]) do
							if not init then
								SNFDEBUG(0, "Loot for "..(name or "nil"))
								init = true
							end
							SNFMessage:QueueTell("    "..bidlevel..", "..raidid..": "..(loot["item"] or "nil"), name)
						end
					end
				end
			end
		end
	end
	if not init then
		SNFMessage:QueueTell("No loot listed for "..(rname or "nil"), name)
	end
end

--[[ Copy for reference
local SpecialReportMatchStrings = {
		{ match = ".*Mark of Sanctification.*", group = "ICCN" },
	}

]]--
function SNFLoot:CheckForSpecialReport(item, n, bidlevel)

	-- Only trigger this special report for UPG and BIS bids.
	if not (bidlevel == "UPG" or bidlevel == "BIS") then return end

	--NEED to figure out which string to match against
	local specialstring = nil

	for _, matchitem in ipairs(SpecialReportMatchStrings) do
		if (item and strmatch(item, matchitem["match"])) then
			specialstring = matchitem["match"]
		end
	end

	if not specialstring then return end

	--otherwise this is a special item and we need to gather special counts.

	if not (item and n and bidlevel) then
		SNFDEBUG(1, "Bad parameter to SNFLoot:CheckForSpecialReport("..(item or "nil")..","..(n or "nil")..","..(bidlevel or "nil")..")")
	end

	local name = SNFPlayer:GetPlayerMain(n)

	if not SNFDKPItems[name] then
		SNFDEBUG(2, "Player "..name.." does not have any calculated loot counts")
		return
	end
	local criteria, compareval = SNFFilter:GetFilterSettings("attend")
	local count = 0 -- have to have this to indicate a special loot, even if it might be zero.

	for _, bidlevel in ipairs({ "UPG", "BIS" }) do -- check both UPG and BIS counts
		if SNFDKPItems[name][bidlevel] then
			local list = SNFDKPItems[name][bidlevel]

			if list and list["Raids"] then
				for r, data in pairs(list["Raids"]) do
					if r and type(data) == "table" and data["Count"] then
						--Note that we don't check date or other comparison strings. Token loot is counted from wherever it is.
						if data["Loots"] then
							for _, ilist in ipairs(data["Loots"]) do
								if ilist["item"] and strmatch(ilist["item"], specialstring) then
									count = count + 1
								end
							end
						end
					end
				end
			end
		end
	end

	return count
end

